4

Here's a full copy of my HTML page, so you can see what I'm talking about:

<!doctype html>

<html lang="en">
<head>
<meta charset="utf-8">
<title>Test Page</title>
<meta name="robots" content="noindex, nofollow">

<script type="text/javascript">
_atrk_opts = { atrk_acct:"/123456", domain:"example.com",dynamic: true};
(function() { var as = document.createElement('script'); as.type = 'text/javascript'; as.async = true; as.src = "https://123.cloudfront.net/sample.js"; var s = document.getElementsByTagName('script')[0];s.parentNode.insertBefore(as, s); })();
</script>

<script type="text/javascript">
_atrk_opts = { atrk_acct:"/tester", domain:"other.com",dynamic: true};
(function() { var as = document.createElement('script'); as.type = 'text/javascript'; as.async = true; as.src = "https://123.cloudfront.net/sample.js"; var s = document.getElementsByTagName('script')[0];s.parentNode.insertBefore(as, s); })();
</script>

<script>
  (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
  (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
  m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
  })(window,document,'script','https://www.google-analytics.com/analytics.js','ga');

  ga('create', 'UA-91071000-1', 'auto');
  ga('send', 'pageview');

</script>

</head>

<body>
<script>
window.location = "http://test.com";
</script>
</body>

</html>

I have 3 scripts in the header that I need to fully run before the Javascript redirect in the body is run.

All of the scripts load pixels and are used for analytics tracking. Basically the problem I'm having is that only a percentage of visitors are being tracked because the redirect in the body is running before the snippets in the header are completed.

I would prefer a solution that guarantees the javascript is run before actually redirecting a visitor - I'm away that I could setup a timer to run my redirect after X seconds, but there's no way to know if the other scripts are done (although they should be very quick).

Any advice or solutions would be great. Thanks!

3
  • "but there's no way to know if other scripts are done", Have you looked at the documentation for the analytics packages you are using? Google Analytics itself has a hitCallback which will trigger a callback once a hit is done sending to their server. Commented Feb 26, 2017 at 20:42
  • I have, but unfortunately the other 2 trackers don't have any option like that :( Commented Feb 26, 2017 at 20:45
  • The first two scripts are easy and identical. The script before the loader _atrk_opts will always be the value of the second declaration. So just add one script tag just after a script that sets _atrk_opts to the second value. replacing the first two scripts with.<script>_atrk_opts = { atrk_acct:"/tester", domain:"other.com",dynamic: true};</script><script src ="https://123.cloudfront.net/sample.js"></script> Then remove the last 4 lines in the anon function and add the <script src='https://www.google-analytics.com/analytics.js'> after 3rd script. then use onload to run your redirect Commented Feb 26, 2017 at 21:09

3 Answers 3

1

If all of the analytics api's do not support a callback for when the hit is complete then you will need to add one yourself.

Either download and modify their analytics js file and use that instead of the injection code you currently have. Or don't use their code at all and just build the image url's with the required information yourself.

In both cases you need to use the urls to send the request to the analytics server and then when finished do the redirect. On modern browsers use the Promise and the Fetch api:

//so either in the analytics code or your own manual code
var img = new Image();
var analyticsUrl = "http://analytics.example.com/?id="+yourid+"&os="+useros+"&country="+usercountry;

fetch( new Request(analyticsUrl,{mode:"no-cors"}) ).then(()=>{
   window.location = "your url";
});

//In the case of multiple analytics packages you would just put the fetches in an array and pass it to Promise.all

var promise1 = fetch( new Request(analyticsUrl1,{mode:"no-cors"}) );
var promise2 = fetch( new Request(analyticsUrl2,{mode:"no-cors"}) );
var promise3 = fetch( new Request(analyticsUrl3,{mode:"no-cors"}) );
Promise.all([ promise1, promise2, promise3 ]).then(()=>{
   window.location = "your url";
});

On older browsers these may not be supported.

So if you are wanting to support these older browsers you will need to add an onload event listener onto the images that get added to the dom instead. In the event listeners you would then need to test wither or not the others are done as well and then do the redirection if so.

var loaded = 0;
function onAnalyticsLoad(){
   loaded++;
   if(loaded >= 3){ 
      window.location = "your url"; 
   }
}
//don't care if there was an error or not, just care that 
//the request had at least time to finish so use both onload and onerror.
analyticsImg1.onload = analyticsImg1.onerror = onAnalyticsLoad;
analyticsImg2.onload = analyticsImg2.onerror = onAnalyticsLoad;
analyticsImg3.onload = analyticsImg3.onerror = onAnalyticsLoad;
Sign up to request clarification or add additional context in comments.

Comments

1

The 3 functions are running asynchronously. You could modify your page redirect code in the body to check for a result from these functions before proceeding.

For example, it looks like these 3 functions insert new nodes into the document, so you could have your code check at regular intervals for their presence along the lines of:

var timer = setTimeout(function(){
   // Check for elements
   if(document.querySelector(...)){
     // Elements(s) exist, cancel timer
     clearTimeout(timer);

     // Proceed with rest of code
   }
}, 1000);

Also, there is no need to separate them into separate <script> elements.

Comments

1

You could either use a setTimeout() to delay the script by a few seconds:

setTimeout(function(){
  window.location = "http://test.com";
}, 3000); // Delays the execution by 3 seconds

Or alternatively, if you have access to jQuery, it would be preferable to use .ready() to ensure that the page has fully loaded:

$(document).ready(function() {
    window.location = "http://test.com";
});

Google Analytics also has a hitCallback that you can use to ensure their scripts have finished running, which you can check against by adding an event listener:

var body = document.getElementById('body');
body.addEventListener('submit', function(event) {
  event.preventDefault();
  ga('send', 'event', 'pageview', 'submit', {
    hitCallback: function() {
      window.location = "http://test.com";
    }
  });
});

This will ensure that the Analytics actually runs before the redirect happens.

Hope this helps! :)

5 Comments

With a hard-coded delay, this puts you at the mercy of network latency though.
I can use jQuery if needed. Does .ready() make sure all other scripts above it have been run? I couldn't tell if it just checks to see if the Javascript has been downloaded or actually fully run...
document.ready doesn't work for dynamically inserted scripts.
It's true that a hard-coded delay would be subject to latency. .ready will definitely wait untilt he <script> tag is executed, which I assume would mean waiting until the analytics trigger. I've just updated this to showcase an example using Google Analytic's hitCallback, which will only trigger the redirect after a successful hit.
Forcing the user to sit around for three seconds just so you can run your analytics on them is pretty darn user hostile. (Then again forcing them to sit around and wait for any length of time just for that is pretty user hostile)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.