A Drop-In Fix For Google Analytics

It's easy, simple, and free. There's no log-in, no load-speed penalty, no JQuery, and no BS.
🔙 to jackgiffin.com

Follow these steps in order to setup IP-address tracking on your website

  1. Confirm whether you want to include the user's 🌐 Time Zone (check=yes, empty=no): 🌐

  2. Confirm whether you want to include maximum support for   Internet Explorer (check=yes, empty=no):  

  3. Confirm whether you want precondition code to reduce 🖧 network load (check=yes, empty=no): 🖧

  4. Confirm whether you want to respect users' 🐾 Do-Not-Track preferences: 🐾

  5. Confirm whether you want precondition code for 🔎 Do-Not-Track: 🔎

  6. Insert the following (X)HTML code as low as you can get it on the page. This is (X)HTML code, not text. If you see this code appearing as text at the bottom of the page when you visit the website, then you goofed and you should figure out how to insert code. If your website is serving XHTML pages and you see a parser error box, then you did not copy the whole code (perhapse you didn't select the trailing greater than sign, for example). However, the code below will only work in IE9+. Internet Explorer 8 and lower are unsupported.

    <img src="data:null" height="0" onerror="(parseInt(navigator.doNotTrack||navigator.msDoNotTrack,35)%42167)!=1&&/(^\?|\x26)(Vj2x=nTvb|arrived-from-ad=1)(\x26|$)/.test(location.search)?this.nextSibling.src='https://jackgiffin.com/main/ip-address-tracker/IPtracker.php?d=0\x26z='+Intl.DateTimeFormat().resolvedOptions().timeZone:0"/><script async="" defer=""></script>
    <img width="0" height="0" onerror="(parseInt(navigator.doNotTrack||navigator.msDoNotTrack,35)%42167)!=1&&/(^\?|\x26)(Vj2x=nTvb|arrived-from-ad=1)(\x26|$)/.test(location.search)?this.nextSibling.src='https://jackgiffin.com/main/ip-address-tracker/IPtracker.php?d=0\x26z='+(Intl.DateTimeFormat().resolvedOptions().timeZone||new Date().toTimeString().split(/[()]/)[1]):0" src="javascript:!0"/><script async="" defer=""></script>

    If you are a Javascript developer and wondering why such a complex solution is needed, then read this paragraph. Otherwise, just be happy with the fact that it works, stay in your merry little land of "the internet causes slow load speeds, not developers", and do not read this paragraph to avoid being lost and confused. The problem with an ordinary <script> tag that links to an external resource is that even with the async="" attribute in supporting browsers, the script still blocks the onload event from firing until the script has finished downloading, thus delaying the presentation of certain websites to the user. As you know, the most common solution to this problem is an inline script that uses document.createElement to dynamically create and inject a script as the page is being parsed so that the script to the external resource does not block the onload event. However, there is a serious problem in this solution: inline scripts block the page parsing because the browser cannot be certain whether the script will call document.write and change all the following html structure. Thus, the solution that I have devised is to use an image tag with a faulty src attribute to asynchronously execute javascript code in the onerror attribute. This src must be faulty, not a transparent image, because an inline transparent image would require a data URI—a data URI that is not supported in IE7 and below. I know that Microsoft has officially discontinued support for windows XP, but some people still try to build their websites around IE6.

    There are many different reasons for why a person might want IP addresses. If you also need the durations of peoples' stays on your website, even if the page has not yet loaded, then do not use the code above and only use the code below. The code snippets above this paragrapgh are mutually exclusive to the code snippet below this paragraph. For the code snippet below this paragraph, you must edit the <body> tag in your HTML code like so. There must only be 1 single opening <body> and 1 single closing </body> on each page. This solution below is a bit more complicated and serious than the first solution at the top of the page. Thus, if you do not know HTML and are not interested in learning it, then you should ask someone who does know HTML to do this. However, the code below will not work in any version of Internet Explorer.However, the code below will only work in Internet Explorer 1011+ (which should not be a problem because the rest of your website might not even work in Internet Explorer and there are almost no people anywhere who use Internet Explorer before version 11)

    <body onbeforeunload="if(/(^\?|\x26)(Vj2x=nTvb|arrived-from-ad=1)(\x26|$)/.test(location.search))navigator.sendBeacon('https://jackgiffin.com/main/ip-address-tracker/IPtracker.php?d=0\x26t='+performance.now()+'\x26z='+Intl.DateTimeFormat().resolvedOptions().timeZone,null)">
    <body onbeforeunload="if(/(^\?|\x26)(Vj2x=nTvb|arrived-from-ad=1)(\x26|$)/.test(location.search)){var u='https://jackgiffin.com/main/ip-address-tracker/IPtracker.php?d=0\x26t='+performance.now()+'\x26z='+(Intl.DateTimeFormat().resolvedOptions().timeZone||new Date().toTimeString().split(/[()]/)[1]),n=navigator,x;!n.sendBeacon?((x=new XMLHttpRequest).open('HEAD',u,!1),x.send()):n.sendBeacon(u,null)}">
    <body onbeforeunload="if((parseInt(navigator.doNotTrack||navigator.msDoNotTrack,35)%42167)!=1&&/(^\?|\x26)(Vj2x=nTvb|arrived-from-ad=1)(\x26|$)/.test(location.search))navigator.sendBeacon('https://jackgiffin.com/main/ip-address-tracker/IPtracker.php?d=0\x26t='+performance.now()+'\x26z='+Intl.DateTimeFormat().resolvedOptions().timeZone,null)">
    <body onbeforeunload="if((parseInt(navigator.doNotTrack||navigator.msDoNotTrack,35)%42167)!=1&&/(^\?|\x26)(Vj2x=nTvb|arrived-from-ad=1)(\x26|$)/.test(location.search)){var u='https://jackgiffin.com/main/ip-address-tracker/IPtracker.php?d=0\x26t='+performance.now()+'\x26z='+(Intl.DateTimeFormat().resolvedOptions().timeZone||new Date().toTimeString().split(/[()]/)[1]),n=navigator,x;!n.sendBeacon?((x=new XMLHttpRequest).open('HEAD',u,!1),x.send()):n.sendBeacon(u,null)}">
  7. Study the diagram below; understand the components of a URL.

  8. When the parameters in the diagram above contain "?arrived-from-ad=1" or "?Vj2x=nTvb" (either parameter works equally well), the php on jackgiffin.com (the website that you are currently seeing) will gather the IP address of the user's/client's computer when the browser fetches the script. Then, the script here on jackgiffin.com will append an entry onto the table at the user's IP-address and browser-tag. Then, the script here on jackgiffin.com will send back to the user/client just 196 keystrokes of (Javascript) code to clear the parameters so that if the user refreshes the page, then the user will not be mistaklenly logged as having visited the page via the ad a second time. These 196 keystrokes are the minimal required in order to properly account for all possible circumstances with the URL and with browser compatibility.

    Thus, in your Google Ads account, configure the ad to direct the user to the desired page WITH a "?arrived-from-ad=1" or "?Vj2x=nTvb" added onto the end of the URL. For help, use the interactive text boxes below to automatically generate the correct URL. As you enter text content into the boxes, the new URL for your campaign will generate automatically and simultaneously.
    Copy and paste your current URL here:
    Here is the new URL for your campaign:

  9. Once a visitor visits your website via the ad campaign, refreshing this page will yield your website listed below with the options to download and reset the data. To get the latest data about IP addresses, simply visit this webpage and redownload the data. To open the CSV data file that you just downloaded, use Microsoft Excel in Microsoft Office on Microsoft Windows, LibreOffice Calc in LibreOffice on Linux, or Google Sheets in your browser on the internet.

All Websites' Logs

Compressed Raw Data
Compressed Raw Data


I (Jack Giffin) was very cogniscent of large scale IP tracking when I designed this project. The PHP on the server side was very easy to scale: 4096-byte sliding-window-esk compression and append-mode-only ensure that the PHP on the server will never be overloaded and IPs will never stop being tracked. Thus, the "Compressed Raw Data" link will always work now and for forever. The Javascript running in your browser is a different story. I am very very paranoid about going maximally client side in order to alleviate stress from the server. Thus, although the IP-address data is compressed on the server when it is recieved, when you go to download the data here, the data gets decompressed in this browser via Javascript and not on the server. Javascript was not originally meant to work with large sums of data. Thus, I was forced to design the Javascript here on this page more quickly than future proof. Pieces of text in Javascript have a maximum length of 512MB in Chrome which is stressed by the sheer size of the pretty human-readable data after decompression. The problem is that the entire file to be downloaded must all fit into one piece of text, else there is no other synchronous way as of July of 2019 to download the file on the client side aside and apart from Adobe Flash plugins that work best in Internet Explorer, but which I do not want to muddle into for fear of future incompatibility with the growing number of devices without Adobe Flash. Based upon this fact and assuming that your browser is Chrome, I predict that the maximum IP-addresses that can be downloaded without crashing the browser will be around 2-8 million (e.g. a pretty-print ratio between 1:256 and 1:64) IP-addresses. However, I also predict that progressive lag may start to ensue after roughly a hundread thousand IP-addresses, depending upon your computer's processor-speed, operating system, and volume of background junk. If I am wrong and you are actually approaching these design limits, then please contact me at wowzeryest@gmail.com and I shall see what I can do about putting some more time into a more scalable asynchronous solution like service workers. No payment will be neccecary/expected/wanted: I strongly advocate the ideal of freeware made for fun and not for profit. I have not yet implemented service workers due to the extrordinary amount of hassle that the W3C made them out to be, though if and when they are needed, their implementation will lift all design limitations and restrictions now and for forever.

Addendum: Isn't PHP Ridden With Bugs And Completely Insecure?

No, PHP is not wrong or insecure. Rather, it is how PHP is too often misused that is wrong and insecure. This misusage is exacerbated by the exposure to Javascript that most developers recieve. My knowledge, comprehension, and depth about this topic should demonstrate my worthiness to program PHP correctly. There exist two valleys separated by the biggest hill in all the 2D flat-world of programming. In a valley of meadows and aesthetics live the front-end developers. These people must be trusting easy-going fellows who recognize that minimal undefined behavior will not cause demons to fly out of their noses. The other, more industrial, valley contains all the back-end developers. These are the paranoid meticulous control-freaks who must see any undefined behavior at all as capable of releasing demons from their nose and threatening their very existance. I was born very far into the front end meadows. However, I followed the curisority and thirst for knowledge in my heart, drawing me to within view of the mountain. I learned how to think like a bug-exploiter without loosing sight of my meadowy origins. With insights, immersion, and understanding into the great article, I took the perilous journey to the top of the mountain and have resided there since. Thus, although I still habitate on the meadowy side of the peaks, I present myself as worth of traversing the divide between front end Javascript and back end PHP.