Last active
May 27, 2024 01:25
-
-
Save keithws/cf0c0e924e892cf1ac2524d2615a73b9 to your computer and use it in GitHub Desktop.
Google Tag Manager tag to load GeoIP data into the GTM data layer. Helps with GDPR.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<script src="//js.maxmind.com/js/apis/geoip2/v2.1/geoip2.js"></script> | |
<script> | |
/* | |
* get geographical location data by ip address | |
* uses the free ipify.org services | |
* and the paid Maxmind GeoIP2 Precision services | |
*/ | |
(function (geoip2) { | |
"use strict"; | |
// mark the start of the script loading | |
var start = (new Date()).getTime(); | |
window.dataLayer = window.dataLayer || []; | |
window.dataLayer.push({ | |
"event": "geoip.js", | |
"geoip.start": start | |
}); | |
triggerDOMEvent(document, "geoipjs", { "start": start }); | |
var isGeoIPLoaded, isWindowLoaded; | |
function onWindowLoadAndGeoIPLoad () { | |
if (isGeoIPLoaded && isWindowLoaded) { | |
// push location data into GTM data layer | |
window.dataLayer.push({ | |
"event": "geoip.window.load" | |
}); | |
triggerDOMEvent(document, "geoipwindowload"); | |
} | |
} | |
// there is a possiblity that the document completes loading before now | |
if (document.readyState === "complete") { | |
isWindowLoaded = true; | |
onWindowLoadAndGeoIPLoad(); | |
} else { | |
window.addEventListener("load", function onWindowLoad () { | |
isWindowLoaded = true; | |
onWindowLoadAndGeoIPLoad(); | |
}); | |
} | |
// helper function to push data to data layer | |
function onSuccess (data, doNotSaveData) { | |
// push location data into GTM data layer | |
window.dataLayer.push({ | |
"event": "geoip.load", | |
"geoip.data": data | |
}); | |
triggerDOMEvent(document, "geoipload", data); | |
isGeoIPLoaded = true; | |
onWindowLoadAndGeoIPLoad(); | |
if (!doNotSaveData) { | |
// store data in local storage | |
if (data && data.traits && data.traits.ip_address) { | |
var key = "maxmind.geoip2.data." + data.traits.ip_address; | |
localStorage.setItem(key, JSON.stringify(data)); | |
} | |
} | |
} | |
// helper function to log and throw error | |
function onError (err) { | |
throw new Error(err.code + ": " + err.error); | |
} | |
// helper function to execute once we have the IP address | |
function onIPLoaded (ip) { | |
window.dataLayer.push({ | |
"event": "geoip.ip", | |
"geoip.ip": ip | |
}); | |
triggerDOMEvent(document, "geoipip", { "ip": ip }); | |
// check local storage for geoip data for that IP address | |
var key = "maxmind.geoip2.data." + ip; | |
var data = localStorage.getItem(key); | |
if (data) { | |
// GeoIP data found in local storage | |
try { | |
data = JSON.parse(data); | |
onSuccess(data, true); | |
} catch (err) { | |
throw err; | |
} | |
} else { | |
// fetch GeoIP data from Maxmind | |
geoip2.country(onSuccess, onError); | |
} | |
} | |
var ip = sessionStorage.getItem("ipify.ip"); | |
if (ip) { | |
// use IP address retrived from session cache | |
onIPLoaded(ip); | |
} else { | |
// use ipify.org to get IP address | |
// listen for when the IP address has been loaded by ipfiy | |
window.ipifyCallback = function ipifyCallback (json) { | |
sessionStorage.setItem("ipify.ip", json.ip); | |
onIPLoaded(json.ip); | |
}; | |
// inject the script from ipify.org | |
var newNode, referenceNode; | |
referenceNode = document.getElementsByTagName("script")[0]; | |
newNode = document.createElement("script"); | |
newNode.async = true; | |
newNode.src = "https://api.ipify.org?format=jsonp&callback=ipifyCallback"; | |
referenceNode.parentNode.insertBefore(newNode, referenceNode); | |
} | |
// helper function to trigger native DOM events | |
function triggerDOMEvent (element, type, detail, bubbles, cancelable) { | |
// defaults | |
if (!(element instanceof EventTarget)) { | |
throw new Error("First argument, element, must be an instance of EventTarget."); | |
} | |
bubbles = bubbles || false; | |
cancelable = cancelable || false; | |
var event; | |
if (CustomEvent) { | |
// the modern way | |
event = new CustomEvent(type, { | |
"bubbles": bubbles, | |
"cancelable": cancelable, | |
"detail": detail | |
}); | |
} else { | |
// the old fashioned way to support Internet Explorer | |
event = document.createEvent("Event"); | |
event.initEvent(type, bubbles, cancelable, detail); | |
} | |
// be nice and set the current target | |
event.currentTarget = element; | |
// target can be any Element or other EventTarget. | |
element.dispatchEvent(event); | |
} | |
}(window.geoip2)); | |
</script> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Updated with code to trigger events on the DOM as well as in GTM.