How to delay loading external JS file (Google Analytics)? - javascript

I'm using the following code to load my Google Analytics (external javascript) in a way that is meant to not block rendering.
However, using both YSlow and Safari Web Inspector - the network traffic clearly shows that the ga.js script is still blocking rending.
/*
http://lyncd.com/2009/03/better-google-analytics-javascript/
Inserts GA using DOM insertion of <script> tag and "script onload" method to
initialize the pageTracker object. Prevents GA insertion from blocking I/O!
As suggested in Steve Souder's talk. See:
http://google-code-updates.blogspot.com/2009/03/steve-souders-lifes-too-short-write.html
*/
/* acct is GA account number, i.e. "UA-5555555-1" */
function gaSSDSLoad (acct) {
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www."),
pageTracker,
s;
s = document.createElement('script');
s.src = gaJsHost + 'google-analytics.com/ga.js';
s.type = 'text/javascript';
s.onloadDone = false;
function init () {
pageTracker = _gat._getTracker(acct);
pageTracker._trackPageview();
}
s.onload = function () {
s.onloadDone = true;
init();
};
s.onreadystatechange = function() {
if (('loaded' === s.readyState || 'complete' === s.readyState) && !s.onloadDone) {
s.onloadDone = true;
init();
}
};
document.getElementsByTagName('head')[0].appendChild(s);
}
/* and run it */
gaSSDSLoad("UA-5555555-1");
Any ideas on how I can use JavaScript to delay the loading of the ga.js file, because the code above doesn't appear to do as it intends, until the entire page has been rendered so that I don't block rendering?

/* and run it */
gaSSDSLoad("UA-5555555-1");
Don't “run it” until the page has finished rendering. That is: onload or elsewhere further along. Don't include the above lines in your inline script block itself, or you won't gain anything.

If you use jQuery you can include the run it part in (which is the same as the body onLoad() event):
$(window).load(function() {
/* and run it */
gaSSDSLoad("UA-5555555-1");
});
and if that is not good enough, you run it a second later (for example...):
$(window).load(function() {
setTimeout("run_it()", 1000);
});
function run_it() {
/* and run it */
gaSSDSLoad("UA-5555555-1");
}
Shouldn´t be necessary though...

You can add a listener to the window, document or body's onload event and execute your gaSSDSLoad function at that time.

The code you get from Google Analytics is already non blocking.
Should be something like this:
<script type="text/javascript">
var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-5555555-1']);
_gaq.push(['_trackPageview']);
(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();
</script>
Google suggests to include it before the closing tag.
In general if you want to load other javascripts asyncronously I suggest you use some loader like:
LABjs
or ControlJS

Related

_gaq.push not working in google analytics

ok, so, I have been trying to make _gaq.push work since so long now.
And my corresponding code is as below.
var ext_id = localStorage.ext_id;
var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-xxxxx-xx']);
_gaq.push(['_trackPageview']);
//console.log(_gaq);
(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = chrome.extension.getURL('js/ga.js'); //uncomment this
//ga.src = "js/ga.js"
// ga.src = 'https://ssl.google-analytics.com/ga.js';
document.head.append(ga); // make it head
// var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s); // comment this out
})();
chrome.runtime.onConnect.addListener(function(port) {
console.assert(port.name == "google-analytics");
port.onMessage.addListener(function(response) {
console.log("Message Passing with response",response.category,response.action, response);
// _gaq.push(['_gat._forceSSL']); // remove this
_gaq.push(['_trackEvent', response.category, response.action,ext_id]); // trouble shoot this
console.log(_gaq, "sending this");
});
});
so, the above will be run when there's no activity on the payments page for more than 1 second. And its triggering properly, i.e its executing after 1 second of inactivity on payments page. But, but _gaq.push is showing no trace in the network tab, to make it more obscure, I'm not even getting any error. Can someone pls tell me what I could possibly be doing wrong?
The gaq.push looks fine and should work.
I think your ga.js library is not loading. Maybe since getURL is deprecated? https://developer.chrome.com/extensions/extension#method-getURL

Google Analytics - event tracking code in separate <script> than the page tracking code

On a site I'm working on, the main section of the tracking code is located at the bottom of the pages (not my choice of placement, but that's where it is). That code is the main:
var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-XXXXXXXX-X']);
_gaq.push(['_trackPageview']);
(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();
On one specific page, I want to track an event that gets auto launched on page load. What I have for code at the top of the page (and therefore in a separate tag than the above code) is:
function getFile()
{
if("<%= getFileURL()%>".length>0){
window.location.href = "<%=getFileURL() %>";
var _gaq = _gaq || [];
_gaq.push(['_trackEvent', 'Downloads', '<%= getFileURL()%>']);
}
}
It doesn't seem to be tracking the event though. I'm sure I'm doing something wrong here and I can take some guesses, but it's not clear enough for me to know exactly what I need to change.
Two problems with your code:
You're redirecting before tracking the event. For best results (like #EkoostikMartin mentioned), you'll want a slight delay between the event tracking and redirect.
You've got a local _gaq defined inside getFile(), so you're not talking to the actual Google analytics code.
Try:
function getFile() {
var href = "<%=getFileURL() %>";
if (href.length > 0) {
_gaq.push(['_trackEvent', 'Downloads', href]);
setTimeout(function(){window.location.href = href}, 100);
}
}
You need to delay the redirect. Something like this below has worked for me in the past:
function getFile() {
var href = "<%=getFileURL() %>";
if(href){
_gaq.push(['_trackEvent', 'Downloads', href]);
setTimeout("gotoUrl('" + href + "')", 100);
}
};
function gotoUrl(href) {
window.location.href = href;
};

Google Analytics tracking

I'd like to remove the Google Analytics URL tracking code from the browser bar so that when a user copy / pastes the URL to share they don't bring along all the tracking data with them, which is both useless and able to skew the data down the road.
So I'm using history.js to run replaceState to basically get rid of the tracking data from the URL after a brief pause.
<script type="text/javascript">
setTimeout(function() {
if( window.location.search.indexOf( "utm_campaign" ) >= 1 ) {
window.history.replaceState( null, document.title, window.location.pathname);
}
}, 1000 );
</script>
Does anyone see any possible complications or problems with such a method?
The only problem that you might have is that Google Analytics might not have been fully loaded by the time that your timeout code runs.
With the Google Analytics tracker, there is an API that lets a function be queued after the GA data has been sent off to Google.
You can do something like this:
var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-XXXXX-X']);
_gaq.push(['_trackPageview']);
_gaq.push(function() {
var newPath = location.pathname + location.search.replace(/[?&]utm_[^?&]+/g, "").replace(/^&/, "?") + location.hash;
if (history.replaceState) history.replaceState(null, '', newPath);
});
(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();
Notice line 4, where a function is pushed to the _gaq object.
This function will replace the URL straight after the GA request has been sent.

Browser Update Script

Browser-Update.org provides a nice piece of javascript which alerts users of out-of-date browsers to update them. Unfortunately (a) IE7 is not included in the default list of out-of-date browsers, and (b) the script doesn't work over SSL.
The script they suggest is
<script type="text/javascript">
var $buoop = {}
$buoop.ol = window.onload;
window.onload=function(){
try {if ($buoop.ol) $buoop.ol();}catch (e) {}
var e = document.createElement("script");
e.setAttribute("type", "text/javascript");
e.setAttribute("src", "http://browser-update.org/update.js");
document.body.appendChild(e);
}
</script>
Instead, I'm using external javascript as follows:
app.onload(function() {
if ('https:' === document.location.protocol) return; // Browser Update script is not currently available over SSL.
var $buoop = {vs:{i:7,f:2,o:10.5,s:2,n:9}};
var e = document.createElement('script');
e.setAttribute('type', 'text/javascript');
e.setAttribute('src', 'http://browser-update.org/update.js');
document.body.appendChild(e);
});
To be clear: app.onload() is a nice function which adds functions to the window.onload handler.
This seems to work, but there's an unfortunate side-effect. If the alert is dismissed, it shouldn't show again in that browsing session. With the script above, that doesn't seem to work. On IE7, the alert happens on each page load. Is there a way around that?
var _shown = false;
app.onload(function() {
if(!_shown) {
if ('https:' === document.location.protocol) return; // Browser Update script is not currently available over SSL.
var $buoop = {vs:{i:7,f:2,o:10.5,s:2,n:9}};
var e = document.createElement('script');
e.setAttribute('type', 'text/javascript');
e.setAttribute('src', 'http://browser-update.org/update.js');
document.body.appendChild(e);
_shown = true;
}
});
and if the page is reloading between navigation store it in a cookie or as a session variable.
you could save a cookie when the alert is shown and check every time if that cookie exists before showing the alert.

how can i load <script>'s into an iframe?

I've got the logic working to append into my iframe from the parent
this works:
$('#iframe').load(function() {
$(this).contents().find('#target').append('this text has been inserted into the iframe by jquery');
});
this doesn't
$('#iframe').load(function() {
$(this).contents().find('body').append('<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>');
});
.lf
The problem is something to do with the inserted script tags not being escaped properly.
Half of the javascript is becomes visible in the html, like the first script tag has been abruptly ended.
Maybe the error is with your string, never create a string in javascript with a literal < /script> in it.
$('#iframe').load(function() {
$(this).contents().find('body').append('<scr' + 'ipt type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></scr' + 'ipt>');
});
I'm a bit surprised that isn't working [Edit: No longer surprised at all, see mtrovo's answer.]...but here's what I do, which is mostly non-jQuery per your comment below but still quite brief:
var rawframe = document.getElementById('theframe');
var framedoc = rawframe.contentDocument;
if (!framedoc && rawframe.contentWindow) {
framedoc = rawframe.contentWindow.document;
}
var script = doc.createElement('script');
script.type = "text/javascript";
script.src = "http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js";
framedoc.body.appendChild(script);
Off-topic: I really wouldn't give an iframe (or anything else) the ID "iframe". That just feels like it's asking for trouble (IE has namespace issues, and while I'm not aware of it confusing tag names and IDs, I wouldn't be completely shocked). I've used "theframe" above instead.
Warning: loading script in this manner would make scripts running in main window context
i.e.: if you use window from somescript.js, it would be NOT iframe's window!
$('#iframe').load(function() {
$(this).contents().find('body').append('<scr' + 'ipt type="text/javascript" src="somescript.js"></scr' + 'ipt>');
});
To be able to use iframe context inject script with this:
function insertScript(doc, target, src, callback) {
var s = doc.createElement("script");
s.type = "text/javascript";
if(callback) {
if (s.readyState){ //IE
s.onreadystatechange = function(){
if (s.readyState == "loaded" ||
s.readyState == "complete"){
s.onreadystatechange = null;
callback();
}
};
} else { //Others
s.onload = function(){
callback();
};
}
}
s.src = src;
target.appendChild(s);
}
var elFrame = document.getElementById('#iframe');
$(elFrame).load(function(){
var context = this.contentDocument;
var frameHead = context.getElementsByTagName('head').item(0);
insertScript(context, frameHead, '/js/somescript.js');
}

Categories

Resources