Last updated 2 March 2018.

Every now and then you might be urged to run Google Tag Manager and/or Google Analytics locally, meaning without the benefit of a web server serving your files. In other words, you’re loading an HTML file from your computer in the web browser. You can identify a locally run file by the file:/// protocol in the address bar.

Now, deploying Google Tag Manager onto that file with the hopes of running Google Analytics requests locally isn’t quite simple. Well, actually, the deployment is fairly simple, but customizing it so that it actually sends useful hits requires some tweaking.

Note! You will not be able to run Preview mode with local files. GTM automatically uses relative protocol when downloading the preview library, and relative protocol on local files falls back to file:/// for the HTTP requests. If someone comes up with an elegant workaround, please let me know in the comments!

1. Modify the GTM Container Snippet

First of all, you need to modify the Google Tag Manager container snippet itself. It uses relative protocol in the script loader URLs, and since local files use the file URI scheme, you need to explicitly tell Google Tag Manager from where to fetch the library.

So, if this is the container snippet:

<!-- Google Tag Manager -->
<noscript><iframe src="//www.googletagmanager.com/ns.html?id=GTM-XXXXX"
height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>
<script>(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
'//www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
})(window,document,'script','dataLayer','GTM-XXXXX');</script>
<!-- End Google Tag Manager -->

You can see how the two URLs embedded within (//www.googletagmanager.com/ns.html... in the iframe and //www.googletagmanager.com/gtm.js... in the script loader itself) do not have an explicit protocol set. So, you need to change these two strings to become https://www.googletagmanager.com/ns.html... and https://www.googletagmanager.com/gtm.js..., respectively. That is the only change you need to make to load Google Tag Manager.

So, well done!

2. Configure the Google Analytics Tag(s)

The next step is to configure the Google Analytics Tags. GA places some restrictions on the web browser if loaded with its default settings:

  1. The host making the requests to GA needs to have either http or https as the protocol.

  2. The host must support storing the Client ID in browser cookies.

  3. The host must be able to pass a proper Document Location value (the URL) to Google Analytics.

Each one of these three is violated by local files. First, local files use the file:/// protocol, as stated earlier. Second, web browsers disable cookies when browsing local files. Third, the URL sent by the client to Google Analytics in the Document Location field is the one with the file URI scheme, again, meaning it’s not parsed correctly by GA into a proper page path.

Luckily, Google Analytics has fields that you can set to make it pass all these three checks.

First, you’ll need to create a helper Variable. It’s a Custom JavaScript Variable with the name Empty function and the following code within:

function() {
  return function() {}
}

Next, in your Google Analytics Tags, browse down to Fields to Set, and add the following fields and values:

Field name: checkProtocolTask
Field value: {{Empty function}}

Field name: storage
Field value: none

Field name: page
Field value: {{Page Path}}

The first field tells GA not to check for valid protocol (http or https) when making the request to /collect.

The second field tells GA not to use browser cookies for persisting the Client ID.

The third field tells GA to override the faulty Document Location with the page’s pathname.

And that’s it! With these steps, you can track your Pageviews and Events in your local files, if you are so inclined.

3. Persist Client ID

However, the downside of setting storage : none is that you won’t have a persistent Client ID anymore. Thus, every single page load will reset the Client ID, resulting in a new User and new Session with every single page.

We don’t want that.

Instead, we can hack around that using the browser’s localStorage API to store the Client ID and fetch it with each request.

You’ll need two new Variables.

The first one is a Custom JavaScript Variable with the name JS - Set _clientId, and the following code within:

function() {
  return function() {
    if (window.Storage) {
      window.localStorage.setItem('_clientId', ga.getAll()[0].get('clientId'));
    }
  }
}

The second is a Custom JavaScript Variable with the name JS - Get _clientId, and the following code within:

function() {
  if (window.Storage) {
    return window.localStorage.getItem('_clientId') || undefined;
  }
  return;
}

The first Variable stores the Client ID in the browser’s localStorage, and the second Variable fetches it from the same place (or returns undefined if Client ID isn’t stored).

Finally, in your Google Analytics Tags, go to Fields to Set again, and set the following two fields:

Field name: hitCallback
Field value: {{JS - Set _clientId}}

Field name: clientId
Field value: {{JS - Get _clientId}}

And there you go! Now, the first time a Google Analytics Tag fires, it stores the Client ID created in the process into the browser’s localStorage. For each subsequent Tag, until localStorage is manually purged, the Tags fetch the stored Client ID from localStorage and send it with the requests. This way sessions and users stay intact, and you’ll be able to derive proper insights from the data.

Summary

This hack probably has only marginal use, but it’s still a valid way of tracking Google Analytics in local files. You don’t always have the benefit of (or the skills to deploy) a web server, so running files locally is, if nothing else, a hat tip to the Notepad + FTP content management systems from the 1990s.

Also, you can use the Client ID hack in your regular trackers, too, if you have some reason to avoid browser cookies for persisting data.